#include "myStdio.h"
#include <string.h>
#include <stdlib.h>
#include <malloc.h>
#include <assert.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int my_fflush(MY_FILE *stream)
{
    assert(stream);

    //调用函数 write 将数据写入内核级缓冲区
    int ret = write(stream->fd, stream->outPutBuff, stream->current);   //文件缓冲区 -> 内核缓冲区
    stream->current = 0;

    ret = fsync(stream->fd);    //内核缓冲区 -> 文件

    return ret == -1 ? ret : 0;
}

MY_FILE *my_fopen(const char *path, const char *mode)
{
    int flag = 0;
    //确定打开方式
    if(strcmp(mode, "r") == 0 || strcmp(mode, "r+") == 0)
    { 
        //r / r+
        mode[1] == '+' ? flag |= O_WRONLY : 1;  //加入写
        flag |= O_RDONLY;   //读取
    }
    else
    {
        //w / w+ / a / a+
        mode[1] == '+' ? flag |= O_RDONLY : 1;  //加入读
        
        if(strcmp(mode, "a") == 0)
            flag |= O_APPEND;   //追加
        else if(strcmp(mode, "w") == 0)
            flag |= O_TRUNC;    //清空
        
        flag |= (O_WRONLY | O_CREAT);   //写入+新建
    }

    //打开文件
    mode_t m = 0666;    //权限
    int fd = 0;
    if(flag & O_CREAT)
        fd = open(path, flag, m);    //新建文件需要权限
    else
        fd = open(path, flag);  //普通打开
    
    if(fd == -1) return NULL;   //打开失败，返回空指针

    //申请FILE空间并传出
    MY_FILE* myFile = (MY_FILE*)malloc(sizeof(MY_FILE));  //申请空间
    if(!myFile)
    {
        close(fd);  //申请失败，也要关闭文件，避免占用 fd
        return NULL;
    }

    //初始化
    myFile->fd = fd;
    //myFile->flags = BUFF_NONE;   //无缓冲
    myFile->flags = BUFF_LINE;   //行缓冲
    //myFile->flags = BUFF_ALL;   //全缓冲

    memset(myFile->outPutBuff, '0', NUM);
    myFile->current = 0;    //下标置0

    return myFile;  //返回成功打开的文件（MY_FILE）
}

int my_fclose(MY_FILE *fp)
{
    //刷新缓冲区
    if(fp->current > 0)
        my_fflush(fp);
    
    int ret = close(fp->fd);    //判断是否关闭成功
    free(fp);   //释放空间
    fp = NULL;

    return ret == -1 ? EOF : 0;
}

size_t my_fread(void *ptr, size_t size, size_t nmemb, MY_FILE *stream)
{
    //读取数据至 ptr
    int ret = read(stream->fd, ptr, size * nmemb);

    return ret == -1 ? ret : size * nmemb;
}

size_t my_fwrite(const void *ptr, size_t size, size_t nmemb, MY_FILE *stream)
{
    int ret = 0;

    //判断缓冲区是否需要刷新
    if(stream->current == NUM) ret = my_fflush(stream);

    //写入数据两种清空：缓冲区空间足够、缓冲区空间不够
    size_t user_size = size * nmemb;    //待写入数据大小
    size_t my_size = NUM - stream->current; //缓冲区剩余空间大小
    size_t writen = 0; //成功写入的字节数
    if(user_size <= my_size)
    {
        memcpy(stream->outPutBuff + stream->current, ptr, user_size);
        stream->current += user_size;
        writen = user_size;
    }
    else
    {
        memcpy(stream->outPutBuff + stream->current, ptr, my_size);
        stream->current += my_size;
        writen = my_size;
    }

    if(stream->flags & BUFF_NONE)
        ret = my_fflush(stream);  //无缓冲，实时写入
    else if(stream->flags & BUFF_LINE)
        if(stream->outPutBuff[stream->current - 1] == '\n') ret = my_fflush(stream);  //行缓冲，有 \n 才冲
    else if(stream->flags & BUFF_ALL)
        if(stream->current == NUM) ret = my_fflush(stream);   //全缓冲，写满了就冲

    return ret == -1 ? ret : writen;    //可能写入失败
}